package app.modules.menu.business.service;

import app.modules.common.constant.CommonLockConstants;
import app.modules.menu.constant.MenuLockConstants;
import app.modules.menu.persistence.dao.MenuFunctionRelationDAO;
import app.modules.security.business.service.function.IFunctionService;
import app.modules.security.dto.web.function.WebFunctionDTO;
import jasmine.framework.common.util.CheckUtil;
import jasmine.framework.common.util.CollectionUtil;
import jasmine.framework.context.InitSupport;
import jasmine.framework.context.RuntimeProvider;
import jasmine.framework.lock.annotation.DistributedLock;
import jasmine.security.rbac.model.SecFunction;
import jasmine.security.rbac.model.SecMenuFunctionRelation;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

/**
 * @author mh.z
 */
@Service
public class MenuFunctionRelationService implements IMenuFunctionRelationService, InitSupport {
    private MenuFunctionRelationDAO menuFunctionRelationDAO;
    private IFunctionService functionService;

    public MenuFunctionRelationService(MenuFunctionRelationDAO menuFunctionRelationDAO) {
        this.menuFunctionRelationDAO = menuFunctionRelationDAO;
    }

    @Override
    public void init(RuntimeProvider runtimeProvider) {
        this.functionService = runtimeProvider.getByType(IFunctionService.class);
    }

    /**
     * 查询指定菜单的所有已分配功能
     *
     * @param functionId
     * @return
     */
    public List<WebFunctionDTO> listAssignedFunctions(Long functionId) {
        List<WebFunctionDTO> recordList = menuFunctionRelationDAO.listAssignedFunctions(functionId);

        return recordList;
    }

    /**
     * 删除指定功能的所有菜单分配关系
     *
     * @param functionId
     */
    @Override
    public void deleteByFunctionId(Long functionId) {
        menuFunctionRelationDAO.deleteByFunctionId(functionId);
    }

    /**
     * 分配功能
     *
     * @param menuId
     * @param functionIds
     */
    @DistributedLock(category = MenuLockConstants.LOCK_CATEGORY_MENU_ASSIGN_FUNCTIONS, key = CommonLockConstants.LOCK_KEY_TENANT)
    @Transactional(rollbackFor = Exception.class)
    public void assignFunction(Long menuId, List<Long> functionIds) {
        CheckUtil.notNull(menuId, "menuId null");
        CheckUtil.notNull(functionIds, "functionIds null");

        // 删除指定菜单的所有功能分配关系
        menuFunctionRelationDAO.deleteByMenuId(menuId);

        if (CollectionUtil.isNotEmpty(functionIds)) {
            List<SecFunction> functionList = functionService.listByIds(functionIds);
            Map<Long, SecFunction> functionMap = CollectionUtil.toMap(functionList, SecFunction::getId);
            functionIds = CollectionUtil.chooseToList(functionIds, (functionId) -> {
                return functionMap.containsKey(functionId);
            });

            List<SecMenuFunctionRelation> newRecordList = CollectionUtil.mapToList(functionIds, (functionId) -> {
                SecMenuFunctionRelation newRecord = new SecMenuFunctionRelation();
                newRecord.setMenuId(menuId);
                newRecord.setFunctionId(functionId);

                return newRecord;
            });

            if (CollectionUtil.isNotEmpty(newRecordList)) {
                // 保存菜单和功能的分配关系
                menuFunctionRelationDAO.saveBatch(newRecordList);
            }
        }
    }

}
